package com.turbo.cloud.ums.web.logic;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.turbo.cloud.core.base.PageQuery;
import com.turbo.cloud.core.exception.BusinessException;
import com.turbo.cloud.core.security.utils.SecurityUtil;
import com.turbo.cloud.core.utils.BeanListUtils;
import com.turbo.cloud.core.utils.PageUtil;
import com.turbo.cloud.ums.constants.UMSConstants;
import com.turbo.cloud.starter.utils.RedisUtil;
import com.turbo.cloud.ums.web.entity.*;
import com.turbo.cloud.ums.web.model.permission.*;
import com.turbo.cloud.ums.web.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 权限表 逻辑处理类
 * </p>
 *
 * @author zhangluning
 * @since 2022-08-13
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class PermissionLogic {

    final IUmsPermissionService umsPermissionService;
    final IUmsApiService umsApiService;
    final IUmsRolePermissionRelationService umsRolePermissionRelationService;
    final IUmsPermissionMenuRelationService umsPermissionMenuRelationService;
    final IUmsPermissionComponentRelationService umsPermissionComponentRelationService;
    final IUmsPermissionApiRelationService umsPermissionApiRelationService;
    final RedisUtil redisUtil;

    /**
     * 根据当前系统ID，查询权限分页列表
     *
     * @return Page
     */
    public Page<UmsPermissionVo> queryPermissionPage(PageQuery<UmsPermissionQo> pageQuery) {
        UmsPermissionQo umsPermissionQo = PageUtil.getPageQueryParam(pageQuery, UmsPermissionQo::new);

        LambdaQueryWrapper<UmsPermission> permissionLQW = new LambdaQueryWrapper<>();
        permissionLQW.eq(UmsPermission::getSystemId, SecurityUtil.getCurrentSystemId());

        permissionLQW.like(CharSequenceUtil.isNotBlank(umsPermissionQo.getPermissionNameByLike()), UmsPermission::getPermissionName, umsPermissionQo.getPermissionNameByLike());
        permissionLQW.like(CharSequenceUtil.isNotBlank(umsPermissionQo.getPermissionCodeByLike()), UmsPermission::getPermissionCode, umsPermissionQo.getPermissionCodeByLike());
        permissionLQW.eq(Objects.nonNull(umsPermissionQo.getStateId()), UmsPermission::getStateId, umsPermissionQo.getStateId());

        permissionLQW.orderByAsc(UmsPermission::getSort);
        Page<UmsPermission> permissionPage = umsPermissionService.page(pageQuery.toPage(), permissionLQW);

        Page<UmsPermissionVo> permissionPageView = PageUtil.toPageView(permissionPage, UmsPermissionVo::new);

        return permissionPageView;
    }

    /**
     * 查询权限分页列表，并根据角色ID标记选中
     *
     * @param pageQuery 查询列表
     * @return List
     */
    public Page<UmsPermissionVo> queryPermissionCheckedPageOfRoleId(PageQuery<UmsPermissionQo> pageQuery) {
        UmsPermissionQo umsPermissionQo = PageUtil.getPageQueryParam(pageQuery, UmsPermissionQo::new);

        LambdaQueryWrapper<UmsPermission> permissionLQW = new LambdaQueryWrapper<>();
        permissionLQW.eq(UmsPermission::getSystemId, SecurityUtil.getCurrentSystemId());

        permissionLQW.like(CharSequenceUtil.isNotBlank(umsPermissionQo.getPermissionNameByLike()), UmsPermission::getPermissionName, umsPermissionQo.getPermissionNameByLike());
        permissionLQW.like(CharSequenceUtil.isNotBlank(umsPermissionQo.getPermissionCodeByLike()), UmsPermission::getPermissionCode, umsPermissionQo.getPermissionCodeByLike());
        permissionLQW.eq(Objects.nonNull(umsPermissionQo.getStateId()), UmsPermission::getStateId, umsPermissionQo.getStateId());

        permissionLQW.orderByAsc(UmsPermission::getSort);
        Page<UmsPermission> permissionPage = umsPermissionService.page(pageQuery.toPage(), permissionLQW);
        Page<UmsPermissionVo> permissionPageView = PageUtil.toPageView(permissionPage, UmsPermissionVo::new);

        // 查询角色关联的权限
        LambdaQueryWrapper<UmsRolePermissionRelation> rolePermissionLQW = new LambdaQueryWrapper<>();
        rolePermissionLQW.eq(UmsRolePermissionRelation::getRoleId, umsPermissionQo.getRoleId());

        List<UmsRolePermissionRelation> rolePermissionRelationList = umsRolePermissionRelationService.list(rolePermissionLQW);

        if (!CollectionUtils.isEmpty(rolePermissionRelationList)) {
            for (UmsPermissionVo umsPermissionVo : permissionPageView.getRecords()) {
                for (UmsRolePermissionRelation rolePermissionRelation : rolePermissionRelationList) {
                    if (umsPermissionVo.getId().equals(rolePermissionRelation.getPermissionId())) {
                        umsPermissionVo.setChecked(true);
                        break;
                    }
                }
            }
        }

        return permissionPageView;
    }

    /**
     * 查询权限列表，并根据角色ID标记选中
     *
     * @param roleId 角色Id
     * @return List
     */
    public List<UmsPermissionVo> queryPermissionCheckedListOfRoleId(String roleId) {
        LambdaQueryWrapper<UmsPermission> permissionLQW = new LambdaQueryWrapper<>();
        permissionLQW.eq(UmsPermission::getSystemId, SecurityUtil.getCurrentSystemId());
        permissionLQW.eq(UmsPermission::getStateId, UMSConstants.DICT_STATE_ID_YES);
        permissionLQW.orderByAsc(UmsPermission::getSort);
        List<UmsPermission> permissionList = umsPermissionService.list(permissionLQW);

        List<UmsPermissionVo> permissionVoList = new ArrayList<>();

        if (!CollectionUtils.isEmpty(permissionList)) {
            BeanListUtils.copyList(permissionList, permissionVoList, UmsPermissionVo::new);

            LambdaQueryWrapper<UmsRolePermissionRelation> rolePermissionLQW = new LambdaQueryWrapper<>();
            rolePermissionLQW.eq(UmsRolePermissionRelation::getRoleId, roleId);

            List<UmsRolePermissionRelation> rolePermissionRelationList = umsRolePermissionRelationService.list(rolePermissionLQW);

            if (!CollectionUtils.isEmpty(rolePermissionRelationList)) {
                for (UmsPermissionVo umsPermissionVo : permissionVoList) {
                    for (UmsRolePermissionRelation rolePermissionRelation : rolePermissionRelationList) {
                        if (umsPermissionVo.getId().equals(rolePermissionRelation.getPermissionId())) {
                            umsPermissionVo.setChecked(true);
                            break;
                        }
                    }
                }
            }
        }

        return permissionVoList;
    }

    /**
     * 新增权限
     *
     * @param umsPermissionDo 实体
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean createPermission(UmsPermissionDo umsPermissionDo) {
        UmsPermission umsPermission = new UmsPermission();
        BeanUtils.copyProperties(umsPermissionDo, umsPermission);
        umsPermission.setSystemId(SecurityUtil.getCurrentSystemId());

        boolean result = umsPermissionService.save(umsPermission);
        if (!result) {
            throw new BusinessException("新增权限失败");
        }
        return true;
    }

    /**
     * 修改权限
     *
     * @param umsPermissionDo 实体
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean modifyPermission(UmsPermissionDo umsPermissionDo) {
        UmsPermission umsPermission = new UmsPermission();
        BeanUtils.copyProperties(umsPermissionDo, umsPermission);

        boolean result = umsPermissionService.updateById(umsPermission);
        if (!result) {
            throw new BusinessException("修改权限失败");
        }
        return true;
    }

    /**
     * 开启、关闭权限有效状态
     *
     * @param id 权限ID
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean enabledPermissionStateById(String id) {
        UmsPermission umsPermission = umsPermissionService.getById(id);
        if (Objects.isNull(umsPermission)) {
            throw new BusinessException("权限不存在");
        }

        if (UMSConstants.DICT_STATE_ID_YES.equals(umsPermission.getStateId())) {
            umsPermission.setStateId(0);
        } else {
            umsPermission.setStateId(1);
        }

        boolean result = umsPermissionService.updateById(umsPermission);
        if (!result) {
            throw new BusinessException("修改权限状态失败");
        }
        return true;
    }

    /**
     * 删除权限
     *
     * @param id 权限ID
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean removePermissionById(String id) {

        boolean result = umsPermissionService.removeById(id);

        //删除权限和菜单的关联关系
        LambdaQueryWrapper<UmsPermissionMenuRelation> permissionMenuRelationLQW = new LambdaQueryWrapper<>();
        permissionMenuRelationLQW.eq(UmsPermissionMenuRelation::getPermissionId, id);
        umsPermissionMenuRelationService.remove(permissionMenuRelationLQW);

        //删除权限和组件的关联关系
        LambdaQueryWrapper<UmsPermissionComponentRelation> permissionComponentRelationLQW = new LambdaQueryWrapper<>();
        permissionComponentRelationLQW.eq(UmsPermissionComponentRelation::getPermissionId, id);
        umsPermissionComponentRelationService.remove(permissionComponentRelationLQW);

        //删除权限和接口的关联关系
        LambdaQueryWrapper<UmsPermissionApiRelation> permissionApiRelationLQW = new LambdaQueryWrapper<>();
        permissionApiRelationLQW.eq(UmsPermissionApiRelation::getPermissionId, id);

        //解除（Redis）权限和接口的关联关系
        List<UmsPermissionApiRelation> permissionApiRelationList = umsPermissionApiRelationService.list(permissionApiRelationLQW);

        umsPermissionApiRelationService.remove(permissionApiRelationLQW);

        if (!CollectionUtils.isEmpty(permissionApiRelationList)) {
            List<String> apiIds = permissionApiRelationList.stream().map(UmsPermissionApiRelation::getApiId).toList();
            LambdaQueryWrapper<UmsApi> apiLQW = new LambdaQueryWrapper<>();
            apiLQW.in(UmsApi::getId, apiIds);
            List<UmsApi> umsApiList = umsApiService.list(apiLQW);
            if (!CollectionUtils.isEmpty(umsApiList)) {
                for (UmsApi umsApi : umsApiList) {
                    refreshRedisApiRoleId(umsApi.getId());
                }
            }
        }

        if (!result) {
            throw new BusinessException("删除权限失败");
        }
        return true;
    }

    /**
     * 绑定权限和菜单关系
     *
     * @param umsPermissionMenuRelationDo 实体
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean bindPermissionMenuRelation(UmsPermissionMenuRelationDo umsPermissionMenuRelationDo) {
        if (StrUtil.isNotBlank(umsPermissionMenuRelationDo.getMenuId())) {
            UmsPermissionMenuRelation umsPermissionMenuRelation = new UmsPermissionMenuRelation();
            umsPermissionMenuRelation.setPermissionId(umsPermissionMenuRelationDo.getPermissionId());
            umsPermissionMenuRelation.setMenuId(umsPermissionMenuRelationDo.getMenuId());

            boolean result = umsPermissionMenuRelationService.save(umsPermissionMenuRelation);
            if (!result) {
                throw new BusinessException("保存权限和菜单关系失败");
            }
        } else {
            // 删除权限关联菜单
            LambdaQueryWrapper<UmsPermissionMenuRelation> permissionMenuRelationLQW = new LambdaQueryWrapper<>();
            permissionMenuRelationLQW.eq(UmsPermissionMenuRelation::getPermissionId, umsPermissionMenuRelationDo.getPermissionId());
            // 存在关联就解除关系
            umsPermissionMenuRelationService.remove(permissionMenuRelationLQW);

            if (!CollectionUtils.isEmpty(umsPermissionMenuRelationDo.getMenuIds())) {
                List<UmsPermissionMenuRelation> list = new ArrayList<>();
                for (String menuId : umsPermissionMenuRelationDo.getMenuIds()) {
                    UmsPermissionMenuRelation umsPermissionMenuRelation = new UmsPermissionMenuRelation();
                    umsPermissionMenuRelation.setPermissionId(umsPermissionMenuRelationDo.getPermissionId());
                    umsPermissionMenuRelation.setMenuId(menuId);
                    list.add(umsPermissionMenuRelation);
                }
                boolean result = umsPermissionMenuRelationService.saveBatch(list);
                if (!result) {
                    throw new BusinessException("保存权限和菜单关系失败");
                }
            }
        }
        return true;
    }

    /**
     * 解除绑定权限和菜单关系
     *
     * @param umsPermissionMenuRelationDo 实体
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean unBindPermissionMenuRelation(UmsPermissionMenuRelationDo umsPermissionMenuRelationDo) {
        // 删除权限关联菜单
        LambdaQueryWrapper<UmsPermissionMenuRelation> permissionMenuRelationLQW = new LambdaQueryWrapper<>();
        permissionMenuRelationLQW.eq(UmsPermissionMenuRelation::getPermissionId, umsPermissionMenuRelationDo.getPermissionId());
        permissionMenuRelationLQW.eq(UmsPermissionMenuRelation::getMenuId, umsPermissionMenuRelationDo.getMenuId());
        // 存在关联就解除关系
        boolean result = umsPermissionMenuRelationService.remove(permissionMenuRelationLQW);
        if (!result) {
            throw new BusinessException("解除权限和菜单关系失败");
        }
        return true;
    }

    /**
     * 绑定权限和菜单关系
     *
     * @param umsPermissionComponentRelationDo 实体
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean bindPermissionComponentRelation(UmsPermissionComponentRelationDo umsPermissionComponentRelationDo) {
        if (StrUtil.isNotBlank(umsPermissionComponentRelationDo.getComponentId())) {
            UmsPermissionComponentRelation umsPermissionComponentRelation = new UmsPermissionComponentRelation();
            umsPermissionComponentRelation.setPermissionId(umsPermissionComponentRelationDo.getPermissionId());
            umsPermissionComponentRelation.setMenuId(umsPermissionComponentRelationDo.getMenuId());
            umsPermissionComponentRelation.setComponentId(umsPermissionComponentRelationDo.getComponentId());

            boolean result = umsPermissionComponentRelationService.save(umsPermissionComponentRelation);
            if (!result) {
                throw new BusinessException("保存权限和组件关系失败");
            }
        } else {
            LambdaQueryWrapper<UmsPermissionComponentRelation> permissionComponentRelationLQW = new LambdaQueryWrapper<>();
            permissionComponentRelationLQW.eq(UmsPermissionComponentRelation::getPermissionId, umsPermissionComponentRelationDo.getPermissionId());
            permissionComponentRelationLQW.eq(UmsPermissionComponentRelation::getMenuId, umsPermissionComponentRelationDo.getMenuId());
            // 存在关联就解除关系
            umsPermissionComponentRelationService.remove(permissionComponentRelationLQW);

            if (!CollectionUtils.isEmpty(umsPermissionComponentRelationDo.getComponentIds())) {
                List<UmsPermissionComponentRelation> list = new ArrayList<>();
                for (String componentId : umsPermissionComponentRelationDo.getComponentIds()) {
                    UmsPermissionComponentRelation umsPermissionComponentRelation = new UmsPermissionComponentRelation();
                    umsPermissionComponentRelation.setPermissionId(umsPermissionComponentRelationDo.getPermissionId());
                    umsPermissionComponentRelation.setMenuId(umsPermissionComponentRelationDo.getMenuId());
                    umsPermissionComponentRelation.setComponentId(componentId);

                    list.add(umsPermissionComponentRelation);
                }
                boolean result = umsPermissionComponentRelationService.saveBatch(list);
                if (!result) {
                    throw new BusinessException("保存权限和组件关系失败");
                }
            }
        }

        return true;
    }

    /**
     * 解除绑定权限和菜单关系
     *
     * @param umsPermissionComponentRelationDo 实体
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean unBindPermissionComponentRelation(UmsPermissionComponentRelationDo umsPermissionComponentRelationDo) {
        LambdaQueryWrapper<UmsPermissionComponentRelation> permissionComponentRelationLQW = new LambdaQueryWrapper<>();
        permissionComponentRelationLQW.eq(UmsPermissionComponentRelation::getPermissionId, umsPermissionComponentRelationDo.getPermissionId());
        permissionComponentRelationLQW.eq(UmsPermissionComponentRelation::getMenuId, umsPermissionComponentRelationDo.getMenuId());
        permissionComponentRelationLQW.eq(UmsPermissionComponentRelation::getComponentId, umsPermissionComponentRelationDo.getComponentId());
        // 存在关联就解除关系
        boolean result = umsPermissionComponentRelationService.remove(permissionComponentRelationLQW);
        if (!result) {
            throw new BusinessException("解除权限和组件关系失败");
        }
        return true;
    }

    /**
     * 绑定权限和接口关系
     *
     * @param umsPermissionApiRelationDo 实体
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean bindPermissionApiRelation(UmsPermissionApiRelationDo umsPermissionApiRelationDo) {
        if (StrUtil.isNotBlank(umsPermissionApiRelationDo.getApiId())) {
            UmsPermissionApiRelation umsPermissionApiRelation = new UmsPermissionApiRelation();
            umsPermissionApiRelation.setPermissionId(umsPermissionApiRelationDo.getPermissionId());
            umsPermissionApiRelation.setMenuId(umsPermissionApiRelationDo.getMenuId());
            umsPermissionApiRelation.setApiId(umsPermissionApiRelationDo.getApiId());
            boolean result = umsPermissionApiRelationService.save(umsPermissionApiRelation);
            if (!result) {
                throw new BusinessException("保存权限和接口关系失败");
            }
        } else {
            LambdaQueryWrapper<UmsPermissionApiRelation> permissionApiRelationLQW = new LambdaQueryWrapper<>();
            permissionApiRelationLQW.eq(UmsPermissionApiRelation::getPermissionId, umsPermissionApiRelationDo.getPermissionId());
            permissionApiRelationLQW.eq(UmsPermissionApiRelation::getMenuId, umsPermissionApiRelationDo.getMenuId());
            // 存在关联就解除关系
            umsPermissionApiRelationService.remove(permissionApiRelationLQW);

            if (!CollectionUtils.isEmpty(umsPermissionApiRelationDo.getApiIds())) {
                List<UmsPermissionApiRelation> list = new ArrayList<>();
                for (String apiId : umsPermissionApiRelationDo.getApiIds()) {
                    UmsPermissionApiRelation umsPermissionApiRelation = new UmsPermissionApiRelation();
                    umsPermissionApiRelation.setPermissionId(umsPermissionApiRelationDo.getPermissionId());
                    umsPermissionApiRelation.setMenuId(umsPermissionApiRelationDo.getMenuId());
                    umsPermissionApiRelation.setApiId(apiId);

                    list.add(umsPermissionApiRelation);
                }
                boolean result = umsPermissionApiRelationService.saveBatch(list);
                if (!result) {
                    throw new BusinessException("保存权限和接口关系失败");
                }
            }

            refreshRedisApiRoleId(umsPermissionApiRelationDo.getMenuId());
        }
        return true;
    }

    /**
     * 解除绑定权限和接口关系
     *
     * @param umsPermissionApiRelationDo 实体
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean unBindPermissionApiRelation(UmsPermissionApiRelationDo umsPermissionApiRelationDo) {
        LambdaQueryWrapper<UmsPermissionApiRelation> permissionApiRelationLQW = new LambdaQueryWrapper<>();
        permissionApiRelationLQW.eq(UmsPermissionApiRelation::getPermissionId, umsPermissionApiRelationDo.getPermissionId());
        permissionApiRelationLQW.eq(UmsPermissionApiRelation::getMenuId, umsPermissionApiRelationDo.getMenuId());
        permissionApiRelationLQW.eq(UmsPermissionApiRelation::getApiId, umsPermissionApiRelationDo.getApiId());
        // 存在关联就解除关系
        boolean result = umsPermissionApiRelationService.remove(permissionApiRelationLQW);
        if (!result) {
            throw new BusinessException("解除权限和接口关系失败");
        }
        return true;
    }

    /**
     * 刷新Redis缓存
     *
     * @param menuId Api列表
     */
    private void refreshRedisApiRoleId(String menuId) {
        LambdaQueryWrapper<UmsApi> apiLQW = new LambdaQueryWrapper<>();
        apiLQW.eq(UmsApi::getMenuId, menuId);
        List<UmsApi> umsApiList = umsApiService.list(apiLQW);

        if (!CollectionUtils.isEmpty(umsApiList)) {
            for (UmsApi umsApi : umsApiList) {
                LambdaQueryWrapper<UmsPermissionApiRelation> permissionApiRelationLQWByApiId = new LambdaQueryWrapper<>();
                permissionApiRelationLQWByApiId.eq(UmsPermissionApiRelation::getApiId, umsApi.getId());
                List<UmsPermissionApiRelation> permissionApiRelationList = umsPermissionApiRelationService.list(permissionApiRelationLQWByApiId);

                if (!CollectionUtils.isEmpty(permissionApiRelationList)) {
                    List<String> permissionIds = permissionApiRelationList.stream().map(UmsPermissionApiRelation::getPermissionId).toList();
                    redisUtil.set(UMSConstants.REDIS_KEY_API_PERMISSION_PREFIX + umsApi.getApiUrl(), JSON.toJSONString(permissionIds));
                } else {
                    redisUtil.delete(UMSConstants.REDIS_KEY_API_PERMISSION_PREFIX + umsApi.getApiUrl());
                }
            }
        }
    }
}
